package com.shuyuntu.proposal.controller;

import com.shuyuntu.proposal.security.UseSecurity;
import com.shuyuntu.proposal.util.flow.FlowInfo;
import com.shuyuntu.proposal.util.flow.FlowInfoStorage;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.InputStream;
import java.io.RandomAccessFile;

/**
 * 基于ng-flow(flow.js)的文件上传系统,此是后台
 *
 * Created by limeng on 16/5/17.
 */
@Controller
@RequestMapping("/flowUpload")
public class FlowUploadController {

    public static final String UPLOAD_DIR = "attachments";

    /**
     * 获取指定chunk上传状态的方法
     * @param flowChunkNumber ...
     * @param flowChunkSize ...
     * @param flowTotalSize ...
     * @param flowIdentifier ...
     * @param flowFilename ...
     * @param flowRelativePath ...
     * @param response ...
     * @return state string
     */
    @ResponseBody
    @RequestMapping(method = RequestMethod.GET)
    @UseSecurity(category = "0100")
    public String doGet(
            @RequestParam int flowChunkNumber,
            @RequestParam Integer flowChunkSize,
            @RequestParam Long flowTotalSize,
            @RequestParam String flowIdentifier,
            @RequestParam String flowFilename,
            @RequestParam String flowRelativePath,
            HttpServletResponse response,
            HttpSession session) {

        String base_dir = UPLOAD_DIR;

        // Here we add a ".temp" to every upload file to indicate NON-FINISHED
        String flowFilePath = new File(base_dir, flowIdentifier)
                .getAbsolutePath() + ".temp";

        FlowInfoStorage storage = FlowInfoStorage.getInstance();

        FlowInfo info = storage.get(flowChunkSize, flowTotalSize,
                flowIdentifier, flowFilename, flowRelativePath, flowFilePath);
        if (!info.valid()) {
            storage.remove(info);
            return "invalid!";
        }

        Object fcn = new FlowInfo.flowChunkNumber(flowChunkNumber);

        if (info.uploadedChunks.contains(fcn)) {
            return "Uploaded."; // This Chunk has been Uploaded.
        } else {
            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
            return "404";
        }
    }

    /**
     * Post上传文件时调用的方法
     * @param flowChunkNumber ...
     * @param flowChunkSize ...
     * @param flowTotalSize ...
     * @param flowIdentifier ...
     * @param flowFilename ...
     * @param flowRelativePath ...
     * @param request ...
     * @return string state
     */
    @RequestMapping(method = RequestMethod.POST)
    @ResponseBody
    @UseSecurity(category = "0100")
    public String doPost(
            @RequestParam Integer flowChunkNumber,
            @RequestParam Integer flowChunkSize,
            @RequestParam Long flowTotalSize,
            @RequestParam String flowIdentifier,
            @RequestParam String flowFilename,
            @RequestParam String flowRelativePath,
            HttpServletRequest request,
            HttpSession session) {

        String base_dir = UPLOAD_DIR;

        // Here we add a ".temp" to every upload file to indicate NON-FINISHED
        String flowFilePath = new File(base_dir, flowIdentifier)
                .getAbsolutePath() + ".temp";

        FlowInfoStorage storage = FlowInfoStorage.getInstance();

        FlowInfo info = storage.get(flowChunkSize, flowTotalSize,
                flowIdentifier, flowFilename, flowRelativePath, flowFilePath);
        if (!info.valid()) {
            storage.remove(info);
            return "invalid!";
        }

        RandomAccessFile raf = null;
        try {
            raf = new RandomAccessFile(info.flowFilePath, "rw");
        } catch (Exception e) {
            File dir = new File(UPLOAD_DIR);
            if (!dir.exists()) {
                dir.mkdir();
            }
            File file = new File(info.flowFilePath);
            try {
                file.createNewFile();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            try {
                raf = new RandomAccessFile(info.flowFilePath, "rw");
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
        try {
            // Seek to position
            raf.seek((flowChunkNumber - 1) * info.flowChunkSize);

            // Save to file
            InputStream is = request.getInputStream();
            long readed = 0;
            long content_length = request.getContentLength();
            byte[] bytes = new byte[1024 * 100];
            while (readed < content_length) {
                int r = is.read(bytes);
                if (r < 0) {
                    break;
                }
                raf.write(bytes, 0, r);
                readed += r;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (raf != null) {
                try {
                    raf.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

        // Mark as uploaded.
        info.uploadedChunks.add(new FlowInfo.flowChunkNumber(flowChunkNumber));
        String flag = info.checkIfUploadFinished();
        if (flag != null) { // Check if all chunks uploaded, and
            // change filename
            FlowInfoStorage.getInstance().remove(info);
            return "All finished.";

        } else {
            return "Upload";
        }
    }

}
